#include "PreCompiledHeader.h"
#include "GameState_Server.hpp"
#include "System.hpp"
#include "Renderer.hpp"
#include "Collision.h"
#include "Vector2D.h"
#include "Timer.h"
#include <string>
#include <sstream>
#include "Server.h"

/******************************************************************************/
/*!
	Defines
*/
/******************************************************************************/
const float PI =  float(3.1415926535897932384626433832795);

const unsigned int	GAME_OBJ_NUM_MAX		= 32;			//The total number of different objects (Shapes)

const unsigned int	GAME_OBJ_INST_NUM_MAX	= 15;			//The total number of different game object instances
const unsigned int	BULLET_OBJ_INST_NUM_MAX	= 5;			//The total number of different game object instances
const unsigned int	ASTEROID_OBJ_INST_NUM_MAX	= 10;			//The total number of different game object instances

const unsigned int	NUM_OF_SHIP				= 4;

const unsigned int	SHIP_INITIAL_NUM		= 3;			// initial number of ship lives
const float			SHIP_SIZE				= 30.0f;		// ship size

const float			SHIP_MAX_SPEED			= 50.0f;		// Maximum speed (m/s)
const Vector2D      BOUNDING_RECT_SIZE      ( 1.0f, 1.0f ); //Size of the bounding rectangle


const float			SHIP_ACCEL_FORWARD		= 40.0f;		// ship forward acceleration (in m/s^2)
const float			SHIP_ACCEL_BACKWARD		= -40.0f;		// ship backward acceleration (in m/s^2)
const float			SHIP_ROT_SPEED			= (3.0f * PI);	// ship rotation speed (degree/second)


const float			BULLET_SPEED			= 80.0f;		// bullet speed (m/s)
const float	        BULLET_SIZE             = 10.0f;		//Size of the bullet      
const int           MAX_ASTEROID_ONSCREEN   = 8;            // Maximum number of Aestroid onscreen  

const int			ASTEROID_SIZE			= 30.0f;

#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

static double bulletTime;

static int shipAliveNum = 4;
// -----------------------------------------------------------------------------
enum TYPE
{
	// list of game object types
	
	TYPE_SHIP = 0, 
	TYPE_ASTEROID,
	TYPE_BULLET,
	TYPE_BACKGROUND
};


// -----------------------------------------------------------------------------
// object flag definition
const unsigned long FLAG_ACTIVE				= 0x00000001;

/******************************************************************************/
/*!
	Struct/Class Definitions
*/
/******************************************************************************/

//Game object structure
struct GameObj
{
	unsigned long		type;		// object type
	
};

// ---------------------------------------------------------------------------

//Game object instance structure
struct GameObjInst
{
	GameObj*			pObject;	// pointer to the 'original' shape
	bool				flag;		// bit flag or-ed together
	bool isVisible;
	float				scale;		// scaling value of the object instance
	Vec2				posCurr;	// object current position
	Vec2				velCurr;	// object current velocity
	float				dirCurr;	// object current direction
	AABB				boundingBox;// object bouding box that encapsulates the object
	D3DXMATRIX			transform;	// object transformation matrix: Each frame, 
	// calculate the object instance's transformation matrix and save it here

	unsigned			shipNm;

	// The number of lives left
	int					sShipLives;				
	unsigned			surviveTime;
	
	//void				(*pfUpdate)(void);
	//void				(*pfDraw)(void);
};

static float fRand(float start, float end);

/******************************************************************************/
/*!
	Static Variables
*/
/******************************************************************************/

// list of original object
static GameObj				sGameObjList[GAME_OBJ_NUM_MAX];				// Each element in this array represents a unique game object (shape)
static unsigned long		sGameObjNum;								// The number of defined game objects

// list of object instances
static GameObjInst			sGameObjInstList[GAME_OBJ_INST_NUM_MAX];	// Each element in this array represents a unique game object instance (sprite)
//static unsigned long		sGameObjInstNum;							// The number of used game object instances

// list of Bullet instances
static GameObjInst			sBulletObjInstList[NUM_OF_SHIP][BULLET_OBJ_INST_NUM_MAX];
//static unsigned long		sBulletObjInstNum;							// The number of used game object instances

//list of Asteroid instances
static GameObjInst			sAsteroidObjInstList[ASTEROID_OBJ_INST_NUM_MAX];

// pointer ot the ship object
static GameObjInst*			spShip;										// Pointer to the "Ship" game object instance

// number of ship available (lives 0 = game over)
static long					sShipLives;									// The number of lives left

// the score = number of asteroid destroyed
static unsigned long		sScore;										// Current score

// Flag of the the aestroid. True if there is none. 
static bool NoAsteroid= true; 

//Spawnpoint of the Aestroid
static Vector2D				SpawnPoints[4]; 
// ---------------------------------------------------------------------------
// functions to create/destroy a game object instance
static GameObjInst*			gameObjInstCreate (unsigned long type, float scale, 
											   Vec2* pPos, Vec2* pVel, float dir, unsigned int ShipNum = 0);
static void					gameObjInstDestroy(GameObjInst* pInst);

Server *server = new Server;
unsigned pktSeq = 0;
bool loop = true;
/******************************************************************************/
/*!
	"Load" function of this state
*/
/******************************************************************************/
void GameStateServerLoad(void)
{
	server->Initialize(8000);

	// zero the game object array
	memset(sGameObjList, 0, sizeof(GameObj) * GAME_OBJ_NUM_MAX);
	// No game objects (shapes) at this point
	sGameObjNum = 0;

	// zero the game object instance array
	memset(sGameObjInstList, 0, sizeof(GameObjInst) * GAME_OBJ_INST_NUM_MAX);
	
	//Zero the game object instance array
	memset(sBulletObjInstList, 0, sizeof(GameObjInst) * BULLET_OBJ_INST_NUM_MAX);

	//Zero the game object instance array
	memset(sAsteroidObjInstList, 0, sizeof(GameObjInst) * ASTEROID_OBJ_INST_NUM_MAX);

	// The ship object instance hasn't been created yet, so this "spShip" pointer is initialized to 0
	spShip = 0;

	// load/create the mesh data (game objects / Shapes)
	GameObj* pObj;

	// =====================
	// create the ship 
	// =====================
	pObj		= sGameObjList + sGameObjNum++;
	pObj->type	= TYPE_SHIP;

	
	// =========================
	// create the asteroid 
	// =========================
	pObj		= sGameObjList + sGameObjNum++;
	pObj->type	= TYPE_ASTEROID;

	// =======================
	// create the bullet 
	// =======================
	pObj		= sGameObjList + sGameObjNum++;
	pObj->type	= TYPE_BULLET;

	//create the background
	pObj		= sGameObjList + sGameObjNum++;
	pObj->type	= TYPE_BACKGROUND;

	//back ground as a object.	
	GameObjInst* pInst = gameObjInstCreate(TYPE_BACKGROUND, 900, 0, 0, 0.0f);

	// create the main ship
	Vec2 pos, vel;
	pos.x = -50.0f;	pos.y = 50.0f;
	pInst = gameObjInstCreate(TYPE_SHIP, SHIP_SIZE, &pos, 0, 1);
	pInst->shipNm = 1;
	pInst->isVisible = false;

	// create the second ship
	pos.x = 50.0f;	pos.y = 50.0f;
	pInst = gameObjInstCreate(TYPE_SHIP, SHIP_SIZE, &pos, 0, 0, 2);
	pInst->shipNm = 2;
	pInst->isVisible = false;

	// create the second ship
	pos.x = -50.0f;	pos.y = -50.0f;
	pInst = gameObjInstCreate(TYPE_SHIP, SHIP_SIZE, &pos, 0, 0, 3);
	pInst->shipNm = 3;
	pInst->isVisible = false;

	// create the second ship
	pos.x = 50.0f;	pos.y = -50.0f;
	pInst = gameObjInstCreate(TYPE_SHIP, SHIP_SIZE, &pos, 0, 0, 4);
	pInst->shipNm = 4;
	pInst->isVisible = false;

	// CREATE THE INITIAL ASTEROIDS INSATNCES USING THE "GAMEOBJINSTCREATE" FUNCTION
	//4 initial asteroids instances with defined positions and velocities.
	pos.x = rand() % SYSTEM->GetWindowWidth() - SYSTEM->GetWindowWidth()/2;	
	pos.y = SYSTEM->GetWindowHeight()/2 + SHIP_SIZE/3;
	vel.x = 40.0f;	vel.y = 20.0f;
	pInst = gameObjInstCreate(TYPE_ASTEROID, 30.0f, &pos, &vel, 0.0f);
	pInst->isVisible = false;

	pos.x = rand() % SYSTEM->GetWindowWidth() - SYSTEM->GetWindowWidth()/2; 
	pos.y = -SYSTEM->GetWindowHeight()/2 - SHIP_SIZE/3;
	vel.x = -30.0f;	vel.y = 10.0f;
	pInst = gameObjInstCreate(TYPE_ASTEROID, 25.0f, &pos, &vel, 0.0f);
	pInst->isVisible = false;

	pos.x = SYSTEM->GetWindowWidth()/2 + SHIP_SIZE/3;	
	pos.y = rand() % SYSTEM->GetWindowHeight()/2 - SYSTEM->GetWindowHeight()/2;
	vel.x = 15.0f;	vel.y = -15.0f;
	pInst = gameObjInstCreate(TYPE_ASTEROID, 30.0f, &pos, &vel, 0.0f);
	pInst->isVisible = false;

	pos.x = -SYSTEM->GetWindowWidth()/2 - SHIP_SIZE/3; 
	pos.y = rand() % SYSTEM->GetWindowHeight()/2 - SYSTEM->GetWindowHeight()/2;
	vel.x = -8.0f;	vel.y = -12.0f;
	pInst = gameObjInstCreate(TYPE_ASTEROID, 25.0f, &pos, &vel, 0.0f);
	pInst->isVisible = false;
	
	// reset the score and the number of ship
	sScore      = 0;

	SpawnPoints[0].x= rand() % SYSTEM->GetWindowWidth() - SYSTEM->GetWindowWidth()/2; 
	SpawnPoints[0].y= SYSTEM->GetWindowHeight()/2 + SHIP_SIZE/3;
	
	SpawnPoints[1].x= rand() % SYSTEM->GetWindowWidth() - SYSTEM->GetWindowWidth()/2; 
	SpawnPoints[1].y= -SYSTEM->GetWindowHeight()/2 - SHIP_SIZE/3;;
	
	SpawnPoints[2].x= SYSTEM->GetWindowWidth()/2 + SHIP_SIZE/3;;
	SpawnPoints[2].y= rand() % SYSTEM->GetWindowHeight()/2 - SYSTEM->GetWindowHeight()/2;

	SpawnPoints[3].x= -SYSTEM->GetWindowWidth()/2 - SHIP_SIZE/3;;
	SpawnPoints[3].y= rand() % SYSTEM->GetWindowHeight()/2 - SYSTEM->GetWindowHeight()/2;
}

/******************************************************************************/
/*!
	"Initialize" function of this state
*/
/******************************************************************************/
void GameStateServerInit(void)
{
	// reset the score and the number of ship
	sScore      = 0;
	sShipLives  = SHIP_INITIAL_NUM;
}

void GameStateServerUpdate(void)
{
	if (KEY_DOWN(VK_ESCAPE))
	{
		gGameStateNext = GS_MAINMENU; 
	}

	if(loop)
	{
		if(server->GetNumOfPlayers() < 4)
			return;
		else
		{
			loop = false;
			for(int i = 1; i < 5; ++i)
			{
				if(sGameObjInstList[i].flag)
				{
					sGameObjInstList[i].isVisible = true;
				}
			}

		}
	}

	GameTask *game_task;
	ClientTask client_task;
	unsigned index = 0;

	do
	{
		client_task = server->GetTaskQueue().Pop();
		if(client_task.type != INVALID)
		{
			game_task = reinterpret_cast<GameTask*>(&client_task.buffer);
			if( (game_task->id < 1) || (game_task->id > 4) )
				break;

			index = game_task->id - 1;
			Vec2 added(	cosf(sGameObjInstList[game_task->id].dirCurr), 
						sinf(sGameObjInstList[game_task->id].dirCurr));

			// Handle player's movement
			if(client_task.type & MOVE)
			{
				if(game_task->type & LEFT)
				{
					sGameObjInstList[game_task->id].dirCurr += SHIP_ROT_SPEED * (float)(Timer::GetInstance()->GetDeltaTime());
				}
				else if(game_task->type & RIGHT)
				{
					sGameObjInstList[game_task->id].dirCurr -= SHIP_ROT_SPEED * (float)(Timer::GetInstance()->GetDeltaTime());
				}
				else if(game_task->type & UP)
				{
					// Position
					sGameObjInstList[game_task->id].velCurr += ( SHIP_MAX_SPEED * added);

					//get the normal direction.
					float y = sGameObjInstList[game_task->id].velCurr.x; 
					sGameObjInstList[game_task->id].velCurr.x =  -sGameObjInstList[game_task->id].velCurr.y; 
					sGameObjInstList[game_task->id].velCurr.y = y;		
				}
				else if(game_task->type & FIRE)
				{
					float bullDir = 0.0f;
					Vector2D  bullVel, bullPos;
					GameObjInst* pInst;

					// Get the bullet's direction according to the ship's direction
					bullDir = sGameObjInstList[game_task->id].dirCurr;

					// Set the velocity
					bullVel.x = (cosf(bullDir + 2.0f*3.14f/180.0f) * BULLET_SPEED);
					bullVel.y = (sinf(bullDir + 2.0f*3.14f/180.0f) * BULLET_SPEED);

					float y	  = bullVel.y;
					bullVel.y = bullVel.x;
					bullVel.x = -y;

					//Set the position in front of the ship
					bullPos.x = sGameObjInstList[game_task->id].posCurr.x-BOUNDING_RECT_SIZE.x*0.5f ;
					bullPos.y = sGameObjInstList[game_task->id].posCurr.y;

					gameObjInstCreate(TYPE_BULLET, BULLET_SIZE, &bullPos, &bullVel, bullDir, game_task->id);		

					break;
				}
			}
		}

	}while(client_task.type != INVALID);

	float AccelerateDeccelerate = 0.0f;

	// Shoot a bullet if space is triggered (Create a new object instance)
	bulletTime +=  Timer::GetInstance()->GetDeltaTime();

	// ======================================================
	// update physics of all active game object instances
	//	-- Positions are updated here with the computed velocity
	//  -- Get the bouding rectangle of every active instance:
	//		boundingRect_min = -BOUNDING_RECT_SIZE * instance->scale + instance->pos
	//		boundingRect_max = BOUNDING_RECT_SIZE * instance->scale + instance->pos
	// ======================================================
	for (unsigned long i = 1; i < 5; i++)
	{
		GameObjInst* pInst = &sGameObjInstList[i];
		// skip non-active object
		if ((pInst->flag & FLAG_ACTIVE) == 0)
			continue;

		//Update Ship's position
		pInst->posCurr += 5 * pInst->velCurr * (float)(Timer::GetInstance()->GetDeltaTime());
		pInst->velCurr.x = 0; pInst->velCurr.y = 0;

		//Bouding Box of every active instance
		pInst->boundingBox.min= pInst->posCurr - (BOUNDING_RECT_SIZE * pInst->scale * 0.5f);
		pInst->boundingBox.max= pInst->posCurr + (BOUNDING_RECT_SIZE * pInst->scale * 0.5f);
	}

	//Update Bullet
	for (unsigned long j = 0; j < NUM_OF_SHIP; j++)
	{
		for (unsigned long i = 0; i < BULLET_OBJ_INST_NUM_MAX; i++)
		{
			GameObjInst* pInst = &sBulletObjInstList[j][i];
			// skip non-active object
			if ((pInst->flag & FLAG_ACTIVE) == 0)
				continue;

			pInst->posCurr += 5 * pInst->velCurr * (float)(Timer::GetInstance()->GetDeltaTime());
		
			//Bouding Box of every active instance
			pInst->boundingBox.min= pInst->posCurr - (BOUNDING_RECT_SIZE * pInst->scale * 0.5f);
			pInst->boundingBox.max= pInst->posCurr + (BOUNDING_RECT_SIZE * pInst->scale * 0.5f);

			//If Out of Bound
			if(	pInst->posCurr.x < -SYSTEM->GetWindowWidth()/2 - SHIP_SIZE/2 ||
					pInst->posCurr.x > SYSTEM->GetWindowWidth()/2 + SHIP_SIZE/2 ||
					pInst->posCurr.y < -SYSTEM->GetWindowHeight()/2 - SHIP_SIZE/2 ||
					pInst->posCurr.y >  SYSTEM->GetWindowHeight()/2 +SHIP_SIZE/2 )
			{
				gameObjInstDestroy(pInst);
			}
		}
	}


	//Update Asteroid
	for (unsigned long i = 0; i < ASTEROID_OBJ_INST_NUM_MAX; i++)
	{
		GameObjInst* pInst = &sAsteroidObjInstList[i];
		// skip non-active object
		if ((pInst->flag & FLAG_ACTIVE) == 0)
			continue;

		pInst->posCurr += 5 * pInst->velCurr * (float)(Timer::GetInstance()->GetDeltaTime());
		
		//Bouding Box of every active instance
		pInst->boundingBox.min= pInst->posCurr - (BOUNDING_RECT_SIZE * pInst->scale * 0.5f);
		pInst->boundingBox.max= pInst->posCurr + (BOUNDING_RECT_SIZE * pInst->scale * 0.5f);

		if(pInst->posCurr.x > SYSTEM->GetWindowWidth()/2 + SHIP_SIZE/2)
		{
			pInst->posCurr.x = -float(SYSTEM->GetWindowWidth())/2;
		}
		else if(pInst->posCurr.x < -SYSTEM->GetWindowWidth()/2 - SHIP_SIZE/2)
		{
			pInst->posCurr.x = float(SYSTEM->GetWindowWidth())/2;
		}
		if(pInst->posCurr.y > SYSTEM->GetWindowHeight()/2 + SHIP_SIZE/2)
		{
			pInst->posCurr.y = -float(SYSTEM->GetWindowHeight())/2;
		}
		else if(pInst->posCurr.y < -SYSTEM->GetWindowHeight()/2 -SHIP_SIZE/2)
		{
			pInst->posCurr.y = float(SYSTEM->GetWindowHeight())/2;
		}
		
	}

	//GAMEOBJECT Mainly Ship
	for (unsigned long i = 1; i < 5; i++)
	{
		GameObjInst* pInst = &sGameObjInstList[i];

		// skip non-active object
		if ((pInst->flag & FLAG_ACTIVE) == 0)
			continue;
		
		if(pInst->posCurr.x > SYSTEM->GetWindowWidth()/2 + SHIP_SIZE/2)
		{
			pInst->posCurr.x = -float(SYSTEM->GetWindowWidth())/2;
		}
		else if(pInst->posCurr.x < -SYSTEM->GetWindowWidth()/2 - SHIP_SIZE/2)
		{
			pInst->posCurr.x = float(SYSTEM->GetWindowWidth())/2;
		}
		if(pInst->posCurr.y > SYSTEM->GetWindowHeight()/2 + SHIP_SIZE/2)
		{
			pInst->posCurr.y = -float(SYSTEM->GetWindowHeight())/2;
		}
		else if(pInst->posCurr.y < -SYSTEM->GetWindowHeight()/2 -SHIP_SIZE/2)
		{
			pInst->posCurr.y = float(SYSTEM->GetWindowHeight())/2;
		}
		
	}

	// ======================================================
	// check for collision
	// ======================================================
	//For each object instance: oi1
	//	if oi1 is not active
	//		skip
	//
	//	if oi1 is an asteroid
	//		for each object instance oi2
	//			if(oi2 is not active or oi2 is an asteroid)
	//				skip
	//
	//			if(oi2 is the ship)
	//				Check for collision between ship and asteroids (Rectangle - Rectangle)
	//				Update game behavior accordingly
	//				Update "Object instances array"
	//			else
	//			if(oi2 is a bullet)
	//				Check for collision between ship and asteroids (Rectangle - Rectangle)
	//				Update game behavior accordingly
	//				Update "Object instances array"
	// ======================================================
	//Asteroid Collision
	for (unsigned long counter = 0; counter < ASTEROID_OBJ_INST_NUM_MAX; ++counter)
	{
		GameObjInst* pInst = sAsteroidObjInstList + counter;
	
		// skip non-active object
		if ((pInst->flag & FLAG_ACTIVE) == 0)
		{
			continue;
		}
			for (unsigned long counter1 = 0; counter1 < GAME_OBJ_INST_NUM_MAX; counter1++)
			{
				GameObjInst* pInst1 = sGameObjInstList + counter1;
				if ((pInst1->flag & FLAG_ACTIVE) == 0 )
					continue;

				else if(pInst1->pObject->type == TYPE_SHIP)
				{
					//If SHIP and Aesteroid collide
					if( CollisionIntersection_RectRect(pInst->boundingBox, pInst->velCurr, 
										               pInst1->boundingBox, pInst1->velCurr) )
					{	
						(pInst1->sShipLives) -= 20;
						gameObjInstDestroy(pInst);

						Vector2D pos, vel;
						pos.x = rand() % SYSTEM->GetWindowWidth() - SYSTEM->GetWindowWidth()/2;	
						pos.y = SYSTEM->GetWindowHeight()/2 + SHIP_SIZE/3;
						vel.x = rand() % 30 - 15;
						vel.y = rand() % 30 - 15;
						pInst = gameObjInstCreate(TYPE_ASTEROID, ASTEROID_SIZE, &pos, &vel, 0.0f);
						pInst->flag = 1;
					}
				}

			}
			for (unsigned long j = 0; j < NUM_OF_SHIP; j++)
			{
				for (unsigned long counter1 = 0; counter1 < BULLET_OBJ_INST_NUM_MAX; counter1++)
				{
					GameObjInst* pInst1 = sBulletObjInstList[j] + counter1;
					if ((pInst1->flag & FLAG_ACTIVE) == 0 )
						continue;

					if(pInst1->pObject->type == TYPE_BULLET)
					{
						if( CollisionIntersection_RectRect(pInst->boundingBox, pInst->velCurr, 
														   pInst1->boundingBox, pInst1->velCurr) )
						{	
								++sScore;
								gameObjInstDestroy(pInst1);
								gameObjInstDestroy(pInst);


								Vector2D pos, vel;
								pos.x = rand() % SYSTEM->GetWindowWidth() - SYSTEM->GetWindowWidth()/2;	
								pos.y = SYSTEM->GetWindowHeight()/2 + SHIP_SIZE/3;
								vel.x = rand() % 30 - 15;
								vel.y = rand() % 30 - 15;
								pInst = gameObjInstCreate(TYPE_ASTEROID,  ASTEROID_SIZE, &pos, &vel, 0.0f);
								pInst->flag = 1;
						}
					}
				}
			}
	}

	for (unsigned long j = 0; j < NUM_OF_SHIP; j++)
	{
		for (unsigned long counter = 0; counter < BULLET_OBJ_INST_NUM_MAX; ++counter)
		{
			GameObjInst* pInst = sBulletObjInstList[j] + counter;
	
			// skip non-active object
			if ((pInst->flag & FLAG_ACTIVE) == 0)
			{
				continue;
			}
		
			if (pInst->pObject->type == TYPE_BULLET)
			{	
				for (unsigned long counter1 = 0; counter1 < GAME_OBJ_INST_NUM_MAX; counter1++)
				{
					GameObjInst* pInst1 = sGameObjInstList + counter1;
					if ((pInst1->flag & FLAG_ACTIVE) == 0  )
					{
						continue;
					}

					else if(pInst1->pObject->type == TYPE_SHIP && pInst1->shipNm != 1)
					{
						//If SHIP and Aesteroid collide
						if( CollisionIntersection_RectRect(pInst->boundingBox, pInst->velCurr, 
							pInst1->boundingBox, pInst1->velCurr) )
						{	
							--(pInst1->sShipLives);
							//	gameObjInstDestroy(pInst);
						}
					}
				}
			}
		}
	}


	// =====================================
	// calculate the matrix for all objects
	// =====================================
	for (unsigned long i = 0; i < GAME_OBJ_INST_NUM_MAX; i++)
	{
		GameObjInst* pInst = sGameObjInstList + i;
		D3DXMATRIX		 trans, rot, scale;

		// skip non-active object
		if ((pInst->flag & FLAG_ACTIVE) == 0)
			continue;

		// Compute the scaling matrix
		D3DXMatrixScaling(&scale, pInst->scale, pInst->scale,1.0f);
		D3DXMatrixRotationZ(&rot,pInst->dirCurr );
		D3DXMatrixTranslation(&trans,pInst->posCurr.x,pInst->posCurr.y,1);
		
		if(pInst->pObject->type == TYPE_BACKGROUND)
			D3DXMatrixTranslation(&trans,pInst->posCurr.x,pInst->posCurr.y,2);

		// Concatenate the 3 matrix in the correct order in the object instance's "transform" matrix
		pInst->transform= scale * rot * trans ;
	}

	// =====================================
	// calculate the matrix for Bullets
	// =====================================
	for (unsigned long j = 0; j < NUM_OF_SHIP; j++)
	{
		for (unsigned long i = 0; i < BULLET_OBJ_INST_NUM_MAX; i++)
		{
			GameObjInst* pInst = sBulletObjInstList[j] + i;
			D3DXMATRIX		 trans, rot, scale;

			// skip non-active object
			if ((pInst->flag & FLAG_ACTIVE) == 0)
				continue;

			// Compute the scaling matrix
			D3DXMatrixScaling(&scale, pInst->scale, pInst->scale,1.0f);
			D3DXMatrixRotationZ(&rot,pInst->dirCurr );
			D3DXMatrixTranslation(&trans,pInst->posCurr.x,pInst->posCurr.y,1);
		
			// Concatenate the 3 matrix in the correct order in the object instance's "transform" matrix
			pInst->transform= scale * rot * trans ;
		}
	}
	// =====================================
	// calculate the matrix for Asteroid
	// =====================================
	for (unsigned long i = 0; i < ASTEROID_OBJ_INST_NUM_MAX; i++)
	{
		GameObjInst* pInst = sAsteroidObjInstList + i;
		D3DXMATRIX		 trans, rot, scale;

		// skip non-active object
		if ((pInst->flag & FLAG_ACTIVE) == 0)
			continue;

		// Compute the scaling matrix
		D3DXMatrixScaling(&scale, pInst->scale, pInst->scale,1.0f);
		D3DXMatrixRotationZ(&rot,pInst->dirCurr );
		D3DXMatrixTranslation(&trans,pInst->posCurr.x,pInst->posCurr.y,1);
		
		// Concatenate the 3 matrix in the correct order in the object instance's "transform" matrix
		pInst->transform= scale * rot * trans ;
	}


	// ======================================================
	// update physics of all bullets object instances
	// ======================================================
	for (unsigned long j = 0; j < NUM_OF_SHIP; j++)
	{
		for (unsigned long i = 0; i < BULLET_OBJ_INST_NUM_MAX; i++)
		{
			GameObjInst* pInst = &sBulletObjInstList[j][i];
			// skip non-active object
			if ((pInst->flag & FLAG_ACTIVE) == 0)
			{
				continue;
			}
			
			pInst->posCurr += pInst->velCurr * (float)(Timer::GetInstance()->GetDeltaTime());

			//Bouding Box of every active instance
			pInst->boundingBox.min= pInst->posCurr - (BOUNDING_RECT_SIZE * pInst->scale * 0.5f);
			pInst->boundingBox.max= pInst->posCurr + (BOUNDING_RECT_SIZE * pInst->scale * 0.5f);
		}
	}

	// ======================================================
	// update physics of all Asteroid object instances
	// ======================================================
	for (unsigned long i = 0; i < ASTEROID_OBJ_INST_NUM_MAX; i++)
	{
		GameObjInst* pInst = &sAsteroidObjInstList[i];
		// skip non-active object
		if ((pInst->flag & FLAG_ACTIVE) == 0)
		{
			continue;
		}
		
		pInst->posCurr += pInst->velCurr * (float)(Timer::GetInstance()->GetDeltaTime());

		//Bouding Box of every active instance
		pInst->boundingBox.min= pInst->posCurr - (BOUNDING_RECT_SIZE * pInst->scale * 0.5f);
		pInst->boundingBox.max= pInst->posCurr + (BOUNDING_RECT_SIZE * pInst->scale * 0.5f);
		
	}

	ServerGameStatus gameState;
	Vector2D pos;

	// Get all the latest position of the player, asteroids, bullets
	// Game status struct to send to player
	for(unsigned i = 1; i < 5; ++i)
	{
		gameState.playerX[i] = sGameObjInstList[i].posCurr.x;
		gameState.playerY[i] = sGameObjInstList[i].posCurr.y;
		gameState.playerFacing[i] = sGameObjInstList[i].dirCurr;
	}

	// Bullets
	for(unsigned j = 0; j < 4; ++j)
		for(unsigned k = 0; k < 5; ++k)
		{
			gameState.BulletX[j][k] = sBulletObjInstList[j][k].posCurr.x;
			gameState.BulletY[j][k] = sBulletObjInstList[j][k].posCurr.y;
			gameState.IsBullet[j][k] = sBulletObjInstList[j][k].flag;
		}

	// Asteroids
	for(unsigned i = 0; i < 10; ++i)
	{
		gameState.asteroidsX[i] = sAsteroidObjInstList[i].posCurr.x;
		gameState.asteroidsY[i] = sAsteroidObjInstList[i].posCurr.y;
		gameState.asteroidFlag[i] = sAsteroidObjInstList[i].flag;
	}

	gameState.type = GAMETASK;
	gameState.seqNum = pktSeq++;
	for(unsigned i = 0; i < server->GetPlayerList().size(); ++i)
	{
		server->GetSocket()->SendUDPData( reinterpret_cast<char*>(&gameState), 
										 sizeof(gameState),
										 server->GetPlayerList()[i]->GetIPAddress(), 
										 server->GetPlayerList()[i]->GetPortNum());
	}

}

static float fRand(float start, float end)
{
	float multiplier = end - start;
	return (((float (rand())/RAND_MAX) * multiplier) + start);
}

void GameStateServerDraw(void)
{
	//win condition
	SYSTEM->GetRenderer()->PrepareToDraw();
	char strBuffer[1024];
	
	//Draw Text
	double fps = Timer::GetInstance()->GetFPS();
	sprintf_s(strBuffer, "FPS: %4f", (fps));
	SYSTEM->GetRenderer()->PrintTextWorld( strBuffer, float(SYSTEM->GetWindowWidth())/2 - 800, 
										float(SYSTEM->GetWindowHeight())/2 -10, WHITE, 500, 10);

	memset(strBuffer, 0, 1024);

	// draw all object instances in the list
	for (unsigned long i = 0; i < GAME_OBJ_INST_NUM_MAX; i++)
	{
		GameObjInst* pInst = &sGameObjInstList[i];

		// skip non-active object
		if (pInst->isVisible = false || (pInst->flag & FLAG_ACTIVE) == 0)
			continue;
		
		// Set the current object instance's transform matrix using "AEGfxSetTransform"
		// Draw the shape used by the current object instance using "AEGfxTriDraw"
		//Draw selected object
		
		//AEGfxSetTransform((AEMtx33 *)&pInst->transform);
		//AEGfxTriDraw(pInst->pObject->pMesh);
		
		

		//draw background
		if(pInst->pObject->type == TYPE_BACKGROUND)
		{
			SYSTEM->GetRenderer()->DrawBackground(pInst->transform);
		}	
		

			if(shipAliveNum == 1 && pInst->sShipLives >0)
		{
			sprintf_s(strBuffer, "Player:%d Won The Game", pInst->shipNm);
			SYSTEM->GetRenderer()->PrintTextWorld( strBuffer, -100.f, -60.f, WHITE, 500, 10);
			memset(strBuffer, 0, 1024);
		}


		//draw ships
		if(pInst->pObject->type==TYPE_SHIP && pInst->shipNm == 1)
		{
			SYSTEM->GetRenderer()->DrawTexture(pInst->transform);
			sprintf_s(strBuffer, "Player 1 HP: %d", pInst->sShipLives);
			SYSTEM->GetRenderer()->PrintTextWorld( strBuffer, float(SYSTEM->GetWindowWidth())/2 - 200, 
										float(SYSTEM->GetWindowHeight())/2 -10, WHITE, 400, 10);
			memset(strBuffer, 0, 1024);
			if( pInst->sShipLives <= 0)
			{
				SYSTEM->GetRenderer()->PrintTextWorld( "You Have Lost The Game!", -100.f, 0.f, WHITE, 500, 10);
				--shipAliveNum;
			}
			memset(strBuffer, 0, 1024);
		}
		if(pInst->pObject->type == TYPE_SHIP && pInst->shipNm == 2)
		{
			SYSTEM->GetRenderer()->DrawTexture2(pInst->transform);
			sprintf_s(strBuffer, "Player 2 HP: %d", pInst->sShipLives);
			SYSTEM->GetRenderer()->PrintTextWorld( strBuffer, float(SYSTEM->GetWindowWidth())/2 - 200, 
										float(SYSTEM->GetWindowHeight())/2 -30, WHITE, 400, 10);
			memset(strBuffer, 0, 1024);
			if( pInst->sShipLives <= 0)
			{
				sprintf_s(strBuffer, "Player:%d Lost The Game", pInst->shipNm);
				SYSTEM->GetRenderer()->PrintTextWorld( strBuffer, -100.f, 0.f, WHITE, 500, 10);
				--shipAliveNum;
			}
			memset(strBuffer, 0, 1024);
		}
		if(pInst->pObject->type == TYPE_SHIP && pInst->shipNm == 3)
		{

			SYSTEM->GetRenderer()->DrawTexture3(pInst->transform);
			sprintf_s(strBuffer, "Player 3 HP: %d", pInst->sShipLives);
			SYSTEM->GetRenderer()->PrintTextWorld( strBuffer, float(SYSTEM->GetWindowWidth())/2 - 200, 
										float(SYSTEM->GetWindowHeight())/2 -50, WHITE, 400, 10);

			memset(strBuffer, 0, 1024);
			if( pInst->sShipLives <= 0)
			{
				sprintf_s(strBuffer, "Player:%d Lost The Game", pInst->shipNm);
				SYSTEM->GetRenderer()->PrintTextWorld( strBuffer, -100.f, 30.f, WHITE, 500, 10);
				--shipAliveNum;
			}
			memset(strBuffer, 0, 1024);
		}
		if(pInst->pObject->type == TYPE_SHIP && pInst->shipNm == 4)
		{
			SYSTEM->GetRenderer()->DrawTexture4(pInst->transform);
			sprintf_s(strBuffer, "Player 4 HP: %d", pInst->sShipLives);
			SYSTEM->GetRenderer()->PrintTextWorld( strBuffer, float(SYSTEM->GetWindowWidth())/2 - 200, 
										float(SYSTEM->GetWindowHeight())/2 -70, WHITE, 400, 10);
			memset(strBuffer, 0, 1024);
			if( pInst->sShipLives <= 0)
			{
				sprintf_s(strBuffer, "Player:%d Lost The Game", pInst->shipNm);
				SYSTEM->GetRenderer()->PrintTextWorld( strBuffer, -100.f, 60.f, WHITE, 500, 10);
				--shipAliveNum;
			}
			memset(strBuffer, 0, 1024);
		}
	}
	// draw all bullet instances in the list
	for (unsigned long j = 0; j < NUM_OF_SHIP; j++)
	{
	for (unsigned long i = 0; i < BULLET_OBJ_INST_NUM_MAX; i++)
	{
		GameObjInst* pInst = sBulletObjInstList[j] + i;

		// skip non-active object
		if (pInst->isVisible = false || (pInst->flag & FLAG_ACTIVE) == 0)
			continue;

		if(pInst->pObject->type == TYPE_BULLET)
		{
			SYSTEM->GetRenderer()->DrawBulletTexture(pInst->transform);
		}

	}
	}

	// draw all Asteroid instances in the list
	for (unsigned long i = 0; i < ASTEROID_OBJ_INST_NUM_MAX; i++)
	{
		GameObjInst* pInst = sAsteroidObjInstList + i;

		// skip non-active object
		if (pInst->isVisible = false || (pInst->flag & FLAG_ACTIVE) == 0)
			continue;
		
		if(pInst->pObject->type == TYPE_ASTEROID)
		{
			SYSTEM->GetRenderer()->DrawAstroid(pInst->transform);
		}

	}

	
	SYSTEM->GetRenderer()->EndDraw();
}

void GameStateServerFree(void)
{
	// kill all object instances in the array using "gameObjInstDestroy"
	for(unsigned long i = 0; i < GAME_OBJ_INST_NUM_MAX; i++)
	{
		GameObjInst* pInst = sGameObjInstList + i;

		gameObjInstDestroy(pInst);
	}

	//Kill Bullet
	for (unsigned long j = 0; j < NUM_OF_SHIP; j++)
	{
		for(unsigned long i = 0; i < GAME_OBJ_INST_NUM_MAX; i++)
		{
			GameObjInst* pInst = sBulletObjInstList[j] + i;
			gameObjInstDestroy(pInst);
		}
	}

	//Kill Asteroid
	for(unsigned long i = 0; i < ASTEROID_OBJ_INST_NUM_MAX; i++)
	{
		GameObjInst* pInst = sAsteroidObjInstList + i;

		gameObjInstDestroy(pInst);
	}
	
}

void GameStateServerUnload(void)
{

}

/******************************************************************************/
/*!
	Create Objects
*/
/******************************************************************************/
GameObjInst* gameObjInstCreate(unsigned long type, float scale, Vec2* pPos, 
													Vec2* pVel, float dir, unsigned int ShipNum)
{
	Vec2 zero(0.0f, 0.0f);
	switch(type)
	{
	case TYPE_SHIP:
		// loop through the object instance list to find a non-used object instance
		for (unsigned long i = 1; i < GAME_OBJ_INST_NUM_MAX; i++)
		{
			GameObjInst* pInst = sGameObjInstList + i;

			// check if current instance is not used
			if (pInst->flag == 0)
			{
				// it is not used => use it to create the new instance
				pInst->pObject	= sGameObjList + type;
				pInst->flag		= FLAG_ACTIVE;
				pInst->scale		= scale;
				pInst->posCurr	= pPos ? *pPos : zero;
				pInst->velCurr	= pVel ? *pVel : zero;
				pInst->dirCurr	= dir;
				pInst->sShipLives = 100;
				// return the newly created instance
				return pInst;
			}
		}
		break;
	case TYPE_ASTEROID:
		// loop through the object instance list to find a non-used object instance
		for (unsigned long i = 0; i < ASTEROID_OBJ_INST_NUM_MAX; i++)
		{
			GameObjInst* pInst = sAsteroidObjInstList + i;

			// check if current instance is not used
			if (pInst->flag == 0)
			{
				// it is not used => use it to create the new instance
				pInst->pObject	= sGameObjList + type;
				pInst->flag		= FLAG_ACTIVE;
				pInst->scale		= scale;
				pInst->posCurr	= pPos ? *pPos : zero;
				pInst->velCurr	= pVel ? *pVel : zero;
				pInst->dirCurr	= dir;
				pInst->sShipLives = 100;
				// return the newly created instance
				return pInst;
			}
		}

		break;
	case TYPE_BULLET:
		// loop through the object instance list to find a non-used object instance
		for (unsigned long i = 0; i < BULLET_OBJ_INST_NUM_MAX; i++)
		{
			GameObjInst* pInst = sBulletObjInstList[ShipNum] + i;

			// check if current instance is not used
			if (pInst->flag == 0)
			{
				// it is not used => use it to create the new instance
				pInst->pObject	= sGameObjList + type;
				pInst->flag		= FLAG_ACTIVE;
				pInst->scale		= scale;
				pInst->posCurr	= pPos ? *pPos : zero;
				pInst->velCurr	= pVel ? *pVel : zero;
				pInst->dirCurr	= dir;
				// return the newly created instance
				return pInst;
			}
		}
		break;
	
	case TYPE_BACKGROUND:
		for (unsigned long i = 0; i < GAME_OBJ_INST_NUM_MAX; i++)
		{
			GameObjInst* pInst = sGameObjInstList + i;

			// check if current instance is not used
			if (pInst->flag == 0)
			{
				// it is not used => use it to create the new instance
				pInst->pObject	= sGameObjList + type;
				pInst->flag		= FLAG_ACTIVE;
				pInst->scale		= scale;
				pInst->posCurr	= pPos ? *pPos : zero;
				pInst->velCurr	= pVel ? *pVel : zero;
				pInst->dirCurr	= dir;
				
				// return the newly created instance
				return pInst;
			}
		}
		break;

	}
	// cannot find empty slot => return 0
	return 0;
}


/******************************************************************************/
/*!
	Destory Objects
*/
/******************************************************************************/
void gameObjInstDestroy(GameObjInst* pInst)
 {
	// if instance is destroyed before, just return
	if (pInst->flag == 0)
		return;

	// zero out the flag
	pInst->flag = 0;
}